home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / PCX_LIB.ARJ / PCX_FILE.C < prev    next >
C/C++ Source or Header  |  1991-04-07  |  49KB  |  1,380 lines

  1. /*
  2.  *************************************************************************
  3.  *
  4.  *  PCX_FILE.C - PCX_LIB Library Image File Functions
  5.  *
  6.  *  Version:    1.00B
  7.  *
  8.  *  History:    91/02/14 - Created
  9.  *              91/04/01 - Release 1.00A
  10.  *              91/04/03 - fixed "segread" call.
  11.  *              91/04/07 - Release 1.00B
  12.  *
  13.  *  Compiler:   Microsoft C V6.0
  14.  *
  15.  *  Author:     Ian Ashdown, P.Eng.
  16.  *              byHeart Software
  17.  *              620 Ballantree Road
  18.  *              West Vancouver, B.C.
  19.  *              Canada V7S 1W3
  20.  *              Tel. (604) 922-6148
  21.  *              Fax. (604) 987-7621
  22.  *
  23.  *  Copyright:  Public Domain
  24.  *
  25.  *************************************************************************
  26.  */
  27.  
  28. /*
  29.  *************************************************************************
  30.  *
  31.  *  PORTABILITY NOTES
  32.  *
  33.  *  1.  While this program is written in ANSI C, it uses a number of 
  34.  *      function calls that are specific to the Microsoft C V6.0 library.
  35.  *      These are documented as follows for the purposes of porting this
  36.  *      program to other compilers and/or processors: 
  37.  *
  38.  *          _ffree      - "free" for small model / far data
  39.  *          _fmalloc    - "malloc" for small model / far data
  40.  *          _fmemcpy    - "memcpy" for small model / far data
  41.  *          int86       - execute 80x86 interrupt routine
  42.  *          int86x      - execute 80x86 interrupt routine (far data)
  43.  *          outpw       - output word to 80x86 I/O port
  44.  *          segread     - get current 80x86 segment register values
  45.  *
  46.  *  2.  When porting this program to other processors, remember that words
  47.  *      are stored by 80x86-based machines in the big-endian format.  That
  48.  *      is, the eight least significant bits (lower byte) are stored
  49.  *      first, followed by the eight most significant bits (upper byte).
  50.  *      If PCX-format files are transferred to little-endian machines
  51.  *      (such as those based on 680x0 and Z8000 processors), the order of
  52.  *      bytes within each word will have to be reversed before they can 
  53.  *      be interpreted.  (This applies to the file header only, since the
  54.  *      encoded image data and optional 256-color palette are stored as
  55.  *      bytes.)
  56.  *
  57.  * 3.   MS-DOS does not recognize the 720 x 348 graphics mode of the
  58.  *      Hercules monochrome display adapter.  Therefore, the constant
  59.  *      PCX_HERC should never be passed as a video mode parameter to any
  60.  *      BIOS service routine.
  61.  *
  62.  *      The Microsoft C compiler includes a "video mode" parameter
  63.  *      definition (_HERCMONO) that is defined as 0x08.  This is a
  64.  *      reserved MS-DOS video mode that is apparently used internally by
  65.  *      the ROM BIOS.  It can, however, be passed to the Microsoft C
  66.  *      library function "_setvideomode" to force the Hercules display
  67.  *      adapter into graphics mode.
  68.  *
  69.  *      Most other MS-DOS C compilers offer similar library functions to
  70.  *      force the Hercules monochrome display adapter into its 720 x 348
  71.  *      graphics mode.
  72.  *
  73.  ************************************************************************* 
  74.  */
  75.  
  76. /*      INCLUDE FILES                                                   */
  77.  
  78. #include <stdio.h>
  79. #include <stdlib.h>
  80. #include <string.h>
  81. #include <conio.h>
  82. #include <malloc.h>
  83. #include <dos.h>
  84. #include <graph.h>
  85. #include "pcx_int.h"
  86.  
  87. /*      FORWARD REFERENCES                                              */
  88.  
  89. static BOOL pcx_encode(int, int, FILE *);
  90. static BOOL pcx_init_palette(PCX_PAL *, int);
  91. static BOOL pcx_write_extpal(FILE *);
  92. static BOOL pcx_write_line(unsigned char *, int, FILE *);
  93. static BOOL pcx_write_init(PCX_WORKBLK *, int, int, int, int);
  94.  
  95. static void pcx_get_cga(PCX_WORKBLK *, unsigned char _far *, int);
  96. static void pcx_get_ega(PCX_WORKBLK *, unsigned char _far *, int);
  97. static void pcx_get_herc(PCX_WORKBLK *, unsigned char _far *, int);
  98. static void pcx_get_vga(PCX_WORKBLK *, unsigned char _far *, int);
  99.  
  100. /*      GLOBALS                                                         */
  101.  
  102. /* Default EGA palette register values                                  */
  103.  
  104. static BYTE pcx_EGA_DefPal_1[16] =      /* Modes 0x0d and 0x0e          */
  105. {
  106.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13,
  107.   0x14, 0x15, 0x16, 0x17
  108. };
  109.  
  110. static BYTE pcx_EGA_DefPal_2[16] =      /* Mode 0x0f                    */
  111. {
  112.   0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
  113.   0x00, 0x18, 0x00, 0x00
  114. };
  115.  
  116. static BYTE pcx_EGA_DefPal_3[16] =      /* Mode 0x10                    */
  117. {
  118.   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a, 0x3b, 
  119.   0x3c, 0x3d, 0x3e, 0x3f
  120. };
  121.  
  122. /*      PUBLIC FUNCTIONS                                                */
  123.  
  124. /*
  125.  *************************************************************************
  126.  *
  127.  *  PCX_WRITE - Write PCX File
  128.  *
  129.  *  Purpose:    To write a PCX-format image file from an image stored in
  130.  *              a video buffer.  The image is assumed to start in the
  131.  *              upper left corner of the screen.
  132.  *
  133.  *  Setup:      BOOL pcx_write
  134.  *              (
  135.  *                char *fname,
  136.  *                int vmode,
  137.  *                int page,
  138.  *                int width,
  139.  *                int height,
  140.  *              )
  141.  *
  142.  *  Where:      fname is a PCX image file name.
  143.  *              vmode is the MS-DOS video mode.  Valid values are:
  144.  *
  145.  *                PCX_HERC -    720 x 348 Hercules monochrome
  146.  *                0x04 -        320 x 200 4-color CGA
  147.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  148.  *                0x06 -        640 x 200 2-color CGA
  149.  *                0x0d -        320 x 200 16-color EGA/VGA
  150.  *                0x0e -        640 x 200 16-color EGA/VGA
  151.  *                0x0f -        640 x 350 2-color EGA/VGA
  152.  *                0x10 -        640 x 350 16-color EGA/VGA
  153.  *                0x11 -        640 x 480 2-color VGA
  154.  *                0x12 -        640 x 480 16-color VGA
  155.  *                0x13 -        320 x 200 256-color VGA
  156.  *
  157.  *              page is the video display page number.  Valid values are:
  158.  *
  159.  *                Mode PCX_HERC - 0 or 1
  160.  *                Mode 0x0d     - 0 to 7
  161.  *                Mode 0x0e     - 0 to 3
  162.  *                Mode 0x0f     - 0 or 1
  163.  *                Mode 0x10     - 0 or 1
  164.  *                All Other     - 0
  165.  *
  166.  *              width is the image width in pixels.
  167.  *              height is the image height in pixels.
  168.  *
  169.  *  Return:     TRUE if successful; otherwise FALSE.
  170.  *
  171.  *************************************************************************
  172.  */
  173.  
  174. BOOL pcx_write
  175. (
  176.   char *fname,
  177.   int vmode,
  178.   int page,
  179.   int width,
  180.   int height
  181. )
  182. {
  183.   int bpline;                   /* Number of bytes per scan line        */
  184.   int line_num;                 /* Scan line number                     */
  185.   unsigned char *linep;         /* Image scan line buffer pointer       */
  186.   BOOL status = TRUE;           /* Return status                        */
  187.   PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  188.  
  189.   /* Open a PCX image file workblock                                    */
  190.  
  191.   if ((wbp = pcx_open(fname, TRUE)) == (PCX_WORKBLK *) NULL)
  192.     return (FALSE);
  193.  
  194.   /* Initialize the workblock for writing                               */
  195.  
  196.   if (pcx_write_init(wbp, vmode, page, width, height) == FALSE)
  197.     status = FALSE;
  198.  
  199.   /* Calculate number of bytes per line (for all color planes)          */
  200.  
  201.   bpline = wbp->header.bppscan * wbp->header.nplanes;
  202.  
  203.   /* Allocate a scan line buffer                                        */
  204.  
  205.   if (status == TRUE)
  206.     if ((linep = (unsigned char *) malloc(bpline)) == (unsigned char *)
  207.         NULL)
  208.       status = FALSE;
  209.  
  210.   /* Write the file header to the file                                  */
  211.  
  212.   if (status == TRUE)
  213.     if (fwrite(&(wbp->header), sizeof(PCX_HDR), 1, wbp->fp) != 1)
  214.       status = FALSE;
  215.  
  216.   /* Write the encoded image data to the file                           */
  217.  
  218.   if (status == TRUE)
  219.   {
  220.     for (line_num = 0; line_num <= (int) wbp->header.ylr; line_num++)
  221.     {
  222.       /* Get the current video buffer scan line                         */
  223.  
  224.       wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  225.  
  226.       /* Encode the scan line and write it to the file                  */
  227.  
  228.       if (pcx_write_line(linep, bpline, wbp->fp) == FALSE)
  229.       {
  230.         status = FALSE;
  231.         break;
  232.       }
  233.     }
  234.   }
  235.  
  236.   if (vmode == 0x13)    /* Is a 256-color palette supported ?           */
  237.   {
  238.     /* Write the extended palette to the file                           */
  239.  
  240.     if (status == TRUE)
  241.       if (pcx_write_extpal(wbp->fp) == FALSE)
  242.         status = FALSE;
  243.   }
  244.  
  245.   if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  246.     status = FALSE;
  247.  
  248.   free(linep);          /* Free the scan line buffer                    */
  249.  
  250.   /* Remove the PCX image file if an error occurred                     */
  251.  
  252.   if (status == FALSE)
  253.     (void) remove(fname);
  254.  
  255.   return (status);
  256. }
  257.  
  258. /*
  259.  *************************************************************************
  260.  *
  261.  *  PCX_INIT_DSA - Initialize Dynamic Save Area
  262.  *
  263.  *  Purpose:    To set up a Video Services Primary Pointer Table and an
  264.  *              associated Dynamic Save Area where BIOS service "Set All
  265.  *              Palette Registers" (function 0x02) can store the EGA color
  266.  *              palette registers settings after it updates them.
  267.  *
  268.  *  Setup:      BOOL pcx_init_dsa
  269.  *              (
  270.  *                PCX_VSB **vsbpp
  271.  *              )
  272.  *
  273.  *  Where:      vsbp is a pointer to where a pointer to an instantiated
  274.  *              PCX_VSB structure is to be returned.
  275.  *
  276.  *  Return:     TRUE if successful; otherwise FALSE.
  277.  *
  278.  *  Note:       The EGA display adapter color palette registers are
  279.  *              write-only.  In order to save the current color palette
  280.  *              with a PCX-format image file by calling "pcx_write", you
  281.  *              must call this function BEFORE you display the image in
  282.  *              the following MS-DOS video modes:
  283.  *
  284.  *                0x0d  - 320 x 200 16-color EGA
  285.  *                0x0e  - 640 x 200 16-color EGA
  286.  *                0x0f  - 640 x 350 2-color EGA
  287.  *                0x10  - 640 x 350 16-color EGA
  288.  *
  289.  *              You MUST call "pcx_free_dsa" upon completion of your
  290.  *              program.   See the function header of "pcx_init_palette"
  291.  *              for more information.
  292.  *
  293.  *************************************************************************
  294.  */
  295.  
  296. BOOL pcx_init_dsa
  297. (
  298.   PCX_VSB **vsbpp
  299. )
  300. {
  301.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  302.   PCX_VSB *vsbp;                /* Video services data save buffer ptr  */
  303.  
  304.   *vsbpp = (PCX_VSB *) NULL;    /* Initialize returned pointer          */
  305.  
  306.   /* Allocate a Dynamic Save Area buffer                                */
  307.  
  308.   if ((dsap = (unsigned char _far *) _fmalloc(sizeof(unsigned char) *
  309.       256)) == (unsigned char _far *) NULL)
  310.     return (FALSE);
  311.  
  312.   /* Allocate a BIOS video services data save buffer                    */
  313.  
  314.   if ((vsbp = (PCX_VSB *) malloc(sizeof(PCX_VSB))) == (PCX_VSB *) NULL)
  315.   {
  316.     _ffree(dsap);       /* Free the Dynamic Save Area buffer            */
  317.     return (FALSE);
  318.   }
  319.  
  320.   /* Save the existing Primary Pointer Table pointer                    */
  321.  
  322.   vsbp->prev_pptp = *((struct pcx_ppt _far * _far *) 0x004000a8L);
  323.  
  324.   /* Copy the existing Primary Pointer Table into the buffer            */
  325.  
  326.   (void) _fmemcpy((struct pcx_ppt _far *) &(vsbp->pcx_ppt),
  327.       vsbp->prev_pptp, sizeof(struct pcx_ppt));
  328.  
  329.   vsbp->pcx_ppt.dsap = dsap;    /* Update the Dynamic Save Area ptr     */
  330.  
  331.   /* Update the Primary Pointer Table pointer in the Video Save Table   */
  332.  
  333.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = &(vsbp->pcx_ppt);
  334.  
  335.   *vsbpp = vsbp;        /* Return Video Services data save buffer ptr   */
  336.  
  337.   return (TRUE);
  338. }
  339.  
  340. /*
  341.  *************************************************************************
  342.  *
  343.  *  PCX_FREE_DSA - Release Dynamic Save Area
  344.  *
  345.  *  Purpose:    To release memory allocated to the Video Services Primary
  346.  *              Pointer Table and associated Dynamic Save Area and reset
  347.  *              the pointer in the Video Save Table.
  348.  *
  349.  *  Setup:      void pcx_free_dsa
  350.  *              (
  351.  *                PCX_VSB *vsbp
  352.  *              )
  353.  *
  354.  *  Where:      vsbp is a pointer to a PCX_VSB structure that was
  355.  *                previously allocated and initialized by "pcx_init_dsa".
  356.  *
  357.  *  Note:       You MUST call this function on completion of your program
  358.  *              if you previously called "pcx_init_dsa".  Failure to do so
  359.  *              will leave the system in an unstable state.  See the
  360.  *              function header of "pcx_init_palette" for more
  361.  *              information.
  362.  *
  363.  *************************************************************************
  364.  */
  365.  
  366. void pcx_free_dsa
  367. (
  368.   PCX_VSB *vsbp
  369. )
  370. {
  371.   /* Restore the previous primary pointer table pointer                 */
  372.  
  373.   *((struct pcx_ppt _far * _far *) 0x004000a8L) = vsbp->prev_pptp;
  374.  
  375.   _ffree(vsbp->pcx_ppt.dsap);   /* Free the Dynamic Save Area           */
  376.  
  377.   free(vsbp);   /* Free the Video Services data save buffer             */
  378. }
  379.  
  380. /*      PRIVATE FUNCTIONS                                               */
  381.  
  382. /*
  383.  *************************************************************************
  384.  *
  385.  *  PCX_WRITE_INIT - Initialize PCX Workblock For Writing
  386.  *
  387.  *  Purpose:    To initialize a PCX image file workblock for writing.
  388.  *
  389.  *  Setup:      static BOOL pcx_write_init
  390.  *              (
  391.  *                PCX_WORKBLK *wbp,
  392.  *                int vmode,
  393.  *                int page,
  394.  *                int width,
  395.  *                int height
  396.  *              )
  397.  *
  398.  *  Where:      wbp is a PCX workblock pointer.
  399.  *              vmode is the MS-DOS video mode.  Valid values are:
  400.  *
  401.  *                0x04 -        320 x 200 4-color CGA
  402.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  403.  *                0x06 -        640 x 200 2-color CGA
  404.  *                Ox07 -        720 x 348 Hercules monochrome
  405.  *                0x0d -        320 x 200 16-color EGA/VGA
  406.  *                0x0e -        640 x 200 16-color EGA/VGA
  407.  *                0x0f -        640 x 350 2-color EGA/VGA
  408.  *                0x10 -        640 x 350 16-color EGA/VGA
  409.  *                0x11 -        640 x 480 2-color VGA
  410.  *                0x12 -        640 x 480 16-color VGA
  411.  *                0x13 -        320 x 200 256-color VGA
  412.  *
  413.  *              page is the video display page number.  Valid values are:
  414.  *
  415.  *                Mode PCX_HERC - 0 or 1
  416.  *                Mode 0x0d     - 0 to 7
  417.  *                Mode 0x0e     - 0 to 3
  418.  *                Mode 0x0f     - 0 or 1
  419.  *                Mode 0x10     - 0 or 1
  420.  *                All Other     - 0
  421.  *
  422.  *              width is the image width in pixels.
  423.  *              height is the image height in pixels.
  424.  *
  425.  *  Return:     TRUE if successful; otherwise FALSE.
  426.  *
  427.  *************************************************************************
  428.  */
  429.  
  430. static BOOL pcx_write_init
  431. (
  432.   PCX_WORKBLK *wbp,
  433.   int vmode,
  434.   int page,
  435.   int width,
  436.   int height
  437. )
  438. {
  439.   int max_width;        /* Maximum image width                          */
  440.   int max_height;       /* Maximum image height                         */
  441.   int shift;            /* Mask shift value                             */
  442.   BOOL status = TRUE;   /* Return status                                */
  443.   PCX_HDR *hdrp;        /* File header buffer pointer                   */
  444.  
  445.   /* Initialize the display page address offset                         */
  446.  
  447.   wbp->page_offset = (unsigned long) 0L;
  448.  
  449.   hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  450.  
  451.   /* Initialize the header constants                                    */
  452.  
  453.   hdrp->pcx_id = 0x0a;          /* PCX format identifier                */
  454.   hdrp->version = 5;            /* Version number                       */
  455.   hdrp->encoding = 1;           /* Encoding format (run-length)         */
  456.   hdrp->xul = 0;                /* Upper left x-position                */
  457.   hdrp->yul = 0;                /* Upper left y-position                */
  458.   hdrp->reserved = 0;           /* (Used to be video mode)              */
  459.   hdrp->palette_type = 1;       /* Color or b&w palette type            */
  460.  
  461.   memset(hdrp->filler, 0, sizeof(hdrp->filler));        /* Padding      */
  462.  
  463.   /* Initialize the video mode-dependent parameters                     */
  464.  
  465.   switch (vmode)
  466.   {
  467.     case PCX_HERC:      /* 720 x 348 Hercules monochrome                */
  468.  
  469.       max_width = min(width, 720);      /* Maximum image width          */
  470.       max_height = min(height, 348);    /* Maximum image height         */
  471.  
  472.       hdrp->bppixel = 1;                /* Bits per pixel               */
  473.       hdrp->horz_res = 720;             /* Horizontal resolution        */
  474.       hdrp->vert_res = 348;             /* Vertical resolution          */
  475.       hdrp->nplanes = 1;                /* Number of color planes       */
  476.  
  477.       /* Maximum two pages supported                                    */
  478.  
  479.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  480.  
  481.       /* Calculate number of bytes to copy                              */
  482.  
  483.       wbp->num_bytes = (max_width + 7) >> 3;
  484.  
  485.       shift = (max_width & 7);  /* Calculate mask shift value           */
  486.  
  487.       wbp->pcx_funcp = pcx_get_herc;    /* Set display capture fcn ptr  */
  488.  
  489.       break;
  490.  
  491.     case 0x04:          /* 320 x 200 4-color CGA                        */
  492.     case 0x05:          /* 320 x 200 4-color CGA (color burst off)      */
  493.  
  494.       max_width = min(width, 320);      /* Maximum image width          */
  495.       max_height = min(height, 200);    /* Maximum image height         */
  496.  
  497.       hdrp->bppixel = 2;                /* Bits per pixel               */
  498.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  499.       hdrp->vert_res = 200;             /* Vertical resolution          */
  500.       hdrp->nplanes = 1;                /* Number of color planes       */
  501.  
  502.       /* Calculate number of bytes to copy                              */
  503.  
  504.       wbp->num_bytes = (max_width + 3) >> 2;
  505.  
  506.       shift = (max_width & 3) << 1;     /* Calculate mask shift value   */
  507.  
  508.       wbp->pcx_funcp = pcx_get_cga;     /* Set display capture fcn ptr  */
  509.  
  510.       break;
  511.  
  512.     case 0x06:          /* 640 x 200 2-color CGA                        */
  513.  
  514.       max_width = min(width, 640);      /* Maximum image width          */
  515.       max_height = min(height, 200);    /* Maximum image height         */
  516.  
  517.       hdrp->bppixel = 1;                /* Bits per pixel               */
  518.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  519.       hdrp->vert_res = 200;             /* Vertical resolution          */
  520.       hdrp->nplanes = 1;                /* Number of color planes       */
  521.  
  522.       /* Calculate number of bytes to copy                              */
  523.  
  524.       wbp->num_bytes = (max_width + 7) >> 3;
  525.  
  526.       shift = (max_width & 7);  /* Calculate mask shift value           */
  527.  
  528.       wbp->pcx_funcp = pcx_get_cga;     /* Set display capture fcn ptr  */
  529.  
  530.       break;
  531.  
  532.     case 0x0d:          /* 320 x 200 16-color EGA/VGA                   */
  533.  
  534.       max_width = min(width, 320);      /* Maximum image width          */
  535.       max_height = min(height, 200);    /* Maximum image height         */
  536.  
  537.       hdrp->bppixel = 1;                /* Bits per pixel               */
  538.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  539.       hdrp->vert_res = 200;             /* Vertical resolution          */
  540.       hdrp->nplanes = 4;                /* Number of color planes       */
  541.  
  542.       /* Maximum eight display pages supported                          */
  543.  
  544.       wbp->page_offset = 0x02000000L * (unsigned long) page;
  545.  
  546.       /* Calculate number of bytes to copy                              */
  547.  
  548.       wbp->num_bytes = (max_width + 7) >> 3;
  549.  
  550.       shift = (max_width & 7);  /* Calculate mask shift value           */
  551.  
  552.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  553.  
  554.       break;
  555.  
  556.     case 0x0e:          /* 640 x 200 16-color EGA/VGA                   */
  557.  
  558.       max_width = min(width, 640);      /* Maximum image width          */
  559.       max_height = min(height, 200);    /* Maximum image height         */
  560.  
  561.       hdrp->bppixel = 1;                /* Bits per pixel               */
  562.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  563.       hdrp->vert_res = 200;             /* Vertical resolution          */
  564.       hdrp->nplanes = 4;                /* Number of color planes       */
  565.  
  566.       /* Maximum four display pages supported                           */
  567.  
  568.       wbp->page_offset = 0x04000000L * (unsigned long) page;
  569.  
  570.       /* Calculate number of bytes to copy                              */
  571.  
  572.       wbp->num_bytes = (max_width + 7) >> 3;
  573.  
  574.       shift = (max_width & 7);  /* Calculate mask shift value           */
  575.  
  576.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  577.  
  578.       break;
  579.  
  580.     case 0x0f:          /* 640 x 350 2-color EGA/VGA                    */
  581.  
  582.       max_width = min(width, 640);      /* Maximum image width          */
  583.       max_height = min(height, 350);    /* Maximum image height         */
  584.  
  585.       hdrp->bppixel = 1;                /* Bits per pixel               */
  586.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  587.       hdrp->vert_res = 350;             /* Vertical resolution          */
  588.       hdrp->nplanes = 2;                /* Number of color planes       */
  589.  
  590.       /* Maximum two display pages supported                            */
  591.  
  592.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  593.  
  594.       /* Calculate number of bytes to copy                              */
  595.  
  596.       wbp->num_bytes = (max_width + 7) >> 3;
  597.  
  598.       shift = (max_width & 7);  /* Calculate mask shift value           */
  599.  
  600.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  601.  
  602.       break;
  603.  
  604.     case 0x10:          /* 640 x 350 16-color EGA/VGA                   */
  605.  
  606.       max_width = min(width, 640);      /* Maximum image width          */
  607.       max_height = min(height, 350);    /* Maximum image height         */
  608.  
  609.       hdrp->bppixel = 1;                /* Bits per pixel               */
  610.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  611.       hdrp->vert_res = 350;             /* Vertical resolution          */
  612.       hdrp->nplanes = 4;                /* Number of color planes       */
  613.  
  614.       /* Maximum two display pages supported                            */
  615.  
  616.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  617.  
  618.       /* Calculate number of bytes to copy                              */
  619.  
  620.       wbp->num_bytes = (max_width + 7) >> 3;
  621.  
  622.       shift = (max_width & 7);  /* Calculate mask shift value           */
  623.  
  624.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  625.  
  626.       break;
  627.  
  628.     case 0x11:          /* 640 x 480 2-color VGA                        */
  629.  
  630.       max_width = min(width, 640);      /* Maximum image width          */
  631.       max_height = min(height, 480);    /* Maximum image height         */
  632.  
  633.       hdrp->bppixel = 1;                /* Bits per pixel               */
  634.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  635.       hdrp->vert_res = 480;             /* Vertical resolution          */
  636.       hdrp->nplanes = 1;                /* Number of color planes       */
  637.  
  638.       /* Calculate number of bytes to copy                              */
  639.  
  640.       wbp->num_bytes = (max_width + 7) >> 3;
  641.  
  642.       shift = (max_width & 7);  /* Calculate mask shift value           */
  643.  
  644.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  645.  
  646.       break;
  647.  
  648.     case 0x12:          /* 640 x 480 16-color VGA                       */
  649.  
  650.       max_width = min(width, 640);      /* Maximum image width          */
  651.       max_height = min(height, 480);    /* Maximum image height         */
  652.  
  653.       hdrp->bppixel = 1;                /* Bits per pixel               */
  654.       hdrp->horz_res = 640;             /* Horizontal resolution        */
  655.       hdrp->vert_res = 480;             /* Vertical resolution          */
  656.       hdrp->nplanes = 4;                /* Number of color planes       */
  657.  
  658.       /* Calculate number of bytes to copy                              */
  659.  
  660.       wbp->num_bytes = (max_width + 7) >> 3;
  661.  
  662.       shift = (max_width & 7);  /* Calculate mask shift value           */
  663.  
  664.       wbp->pcx_funcp = pcx_get_ega;     /* Set display capture fcn ptr  */
  665.  
  666.       break;
  667.  
  668.     case 0x13:          /* 320 x 200 256-color VGA                      */
  669.  
  670.       max_width = min(width, 320);      /* Maximum image width          */
  671.       max_height = min(height, 200);    /* Maximum image height         */
  672.  
  673.       hdrp->bppixel = 8;                /* Bits per pixel               */
  674.       hdrp->horz_res = 320;             /* Horizontal resolution        */
  675.       hdrp->vert_res = 200;             /* Vertical resolution          */
  676.       hdrp->nplanes = 1;                /* Number of color planes       */
  677.  
  678.       /* Calculate number of bytes to copy                              */
  679.  
  680.       wbp->num_bytes = max_width;
  681.  
  682.       shift = 0;        /* Dummy parameter                              */
  683.  
  684.       wbp->pcx_funcp = pcx_get_vga;     /* Set display capture fcn ptr  */
  685.  
  686.       break;
  687.  
  688.     default:            /* Other modes not supported                    */
  689.  
  690.       status = FALSE;
  691.  
  692.       break;
  693.   }
  694.  
  695.   /* Initialize common video mode-dependent parameters                  */
  696.  
  697.   hdrp->xlr = max_width - 1;            /* Lower right x-position       */
  698.   hdrp->ylr = max_height - 1;           /* Lower right y-position       */
  699.   hdrp->scrn_width = hdrp->horz_res;    /* Screen width                 */
  700.   hdrp->scrn_height = hdrp->vert_res;   /* Screen height                */
  701.  
  702.   /* Calculate mask for "white" data                                    */
  703.  
  704.   if (shift != 0)
  705.     wbp->mask = 0xff >> shift;
  706.   else
  707.     wbp->mask = 0x00;
  708.  
  709.   /* Initialize the file header palette                                 */
  710.  
  711.   status = pcx_init_palette(hdrp->palette, vmode);
  712.  
  713.   /* Calculate number of bytes per color plane scan line (must be an    */
  714.   /* even number of bytes)                                              */
  715.  
  716.   hdrp->bppscan = 2 * (((((hdrp->xlr * hdrp->bppixel) + 7) / 8) + 1) / 2);
  717.  
  718.   return (status);
  719. }
  720.  
  721. /*
  722.  *************************************************************************
  723.  *
  724.  *  PCX_INIT_PALETTE - Initialize File Header Palette
  725.  *
  726.  *  Purpose:    To initialize the file header 16-color palette.
  727.  *
  728.  *  Setup:      static BOOL pcx_init_palette
  729.  *              (
  730.  *                PCX_PAL *palettep,
  731.  *                int vmode
  732.  *              )
  733.  *
  734.  *  Where:      palettep is a pointer to the PCX file header buffer
  735.  *                "palette" member.
  736.  *              vmode is the MS-DOS video mode.  Valid values are:
  737.  *
  738.  *                0x04 -        320 x 200 4-color CGA
  739.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  740.  *                0x06 -        640 x 200 2-color CGA
  741.  *                Ox07 -        720 x 348 Hercules monochrome
  742.  *                0x0d -        320 x 200 16-color EGA/VGA
  743.  *                0x0e -        640 x 200 16-color EGA/VGA
  744.  *                0x0f -        640 x 350 2-color EGA/VGA
  745.  *                0x10 -        640 x 350 16-color EGA/VGA
  746.  *                0x11 -        640 x 480 2-color VGA
  747.  *                0x12 -        640 x 480 16-color VGA
  748.  *                0x13 -        320 x 200 256-color VGA
  749.  *
  750.  *  Return:     TRUE if successful; otherwise FALSE.
  751.  *
  752.  *  Note:       The CGA color palette is not supported.
  753.  *
  754.  *              If a VGA display adapter is present, the color palette
  755.  *              registers can be read directly from the adapter using the
  756.  *              BIOS routine "Read All Palette Registers" (function 0x09).
  757.  *
  758.  *              Unfortunately, the EGA display adapter color palette
  759.  *              registers are write-only.  This means that the current
  760.  *              color palette for EGA displays cannot in general be read.
  761.  *
  762.  *              The BIOS routine "Set All Palette Registers" (function
  763.  *              0x02) will write the current palette register values to a
  764.  *              buffer called the Dynamic Save Area.  The EGA color
  765.  *              palette can be read from the first 16 bytes of this 256-
  766.  *              byte RAM block.
  767.  *
  768.  *              The Dynamic Save Area is not statically allocated; it must
  769.  *              be supplied by the user.  The BIOS video services data in
  770.  *              segment 0x40 includes a pointer at address 0040:00a8 that
  771.  *              references the Video Services Primary Pointer Table in the
  772.  *              EGA/VGA BIOS.  This table contains seven pointers, the
  773.  *              second of which is used by the "Set All Palette Registers"
  774.  *              routine to reference the Dynamic Save Area.  Since the
  775.  *              Dynamic Save Area does not exist at system initialization,
  776.  *              the value of this pointer is 0000:0000 (in which case the
  777.  *              the updated palette register values are not saved to RAM
  778.  *              when they are updated).
  779.  *
  780.  *              To utilize the EGA palette register save feature, the
  781.  *              user must perform the following:
  782.  *
  783.  *                1.  Save a copy of the pointer at address 0040:00a8.
  784.  *                2.  Allocate a buffer for a new Primary Pointer Table.
  785.  *                3.  Copy the existing Primary Pointer Table to the
  786.  *                    allocated buffer.
  787.  *                4.  Allocate a 256-byte buffer for a Dynamic Save Area.
  788.  *                5.  Initialize the second pointer of the Primary Pointer
  789.  *                    Table to point to the Dynamic Save Area buffer.
  790.  *
  791.  *              Before the program finishes, the user must also restore
  792.  *              the saved Primary Pointer Table pointer to address
  793.  *              0040:00a8.  Failure to do so will mean that subsequent
  794.  *              calls by other programs to the "Set All Palette
  795.  *              Registers" routine will result in the color palette
  796.  *              registers values being written to unallocated memory (or
  797.  *              memory that has been allocated for another purpose).
  798.  *
  799.  *              The function "pcx_init_dsa" performs the five steps
  800.  *              outlined above, while the function "pcx_free_dsa" restores
  801.  *              the saved pointer on completion of your program.
  802.  *
  803.  *              If the Dynamic Save Area pointer is 0000:0000 (the default
  804.  *              value at system initialization), the BIOS default color
  805.  *              palette settings for the appropriate mode are stored in
  806.  *              the file header color palette.
  807.  *
  808.  *************************************************************************
  809.  */
  810.  
  811. static BOOL pcx_init_palette
  812. (
  813.   PCX_PAL *palettep,
  814.   int vmode
  815. )
  816. {
  817.   int i;                        /* Scratch counter                      */
  818.   int val;                      /* Current palette register value       */
  819.   int red;                      /* Temporary value                      */
  820.   int green;                    /* Temporary value                      */
  821.   int blue;                     /* Temporary value                      */
  822.   unsigned char *ega_palp;      /* EGA/VGA palette buffer pointer       */
  823.   unsigned char _far *dsap;     /* Dynamic Save Area pointer            */
  824.   union REGS regs;              /* 80x86 register values                */
  825.   struct SREGS sregs;           /* 80x86 segment register values        */
  826.  
  827.   if (vmode < 0x0d || vmode > 0x12)
  828.   {
  829.     /* Clear the file header palette                                    */
  830.  
  831.     memset(palettep, 0, sizeof(PCX_PAL) * PCX_PAL_SIZE);
  832.  
  833.     return (TRUE);
  834.   }
  835.  
  836.   /* Allocate a 16-color (plus border color) EGA/VGA palette buffer     */
  837.  
  838.   if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char), 
  839.       (PCX_PAL_SIZE + 1))) == (unsigned char *) NULL)
  840.     return (FALSE);
  841.  
  842.   if (pcx_isvga() == TRUE)      /* Check for VGA display adapter        */
  843.   {
  844.     /* Read the EGA/VGA palette registers                               */
  845.  
  846.     regs.h.ah = 0x10;   /* Select "Read All Palette Registers" routine  */
  847.     regs.h.al = 0x09;
  848.  
  849.     /* Get the EGA/VGA palette buffer offset value                      */
  850.  
  851.     regs.x.dx = (unsigned int) ega_palp;
  852.  
  853.     segread(&sregs);    /* Get the current DS segment register value    */
  854.  
  855.     sregs.es = sregs.ds;
  856.  
  857.     int86x(0x10, ®s, ®s, &sregs);  /* Call BIOS video service     */
  858.   }
  859.   else
  860.   {
  861.     /* Check for a Dynamic Save Area buffer                             */
  862.  
  863.     dsap = *(*((unsigned char _far * _far * _far *) 0x004000a8L) + 1);
  864.  
  865.     if (dsap != (unsigned char _far *) NULL)
  866.     {
  867.       /* Copy the current palette into the local EGA/VGA palette buffer */
  868.  
  869.       (void) _fmemcpy((unsigned char _far *) ega_palp, dsap,
  870.           PCX_PAL_SIZE);
  871.     }
  872.     else
  873.     {
  874.       /* Copy the appropriate default palette settings                  */
  875.  
  876.       switch (vmode)
  877.       {
  878.         case 0x0d:      /* 320 x 200 16-color EGA                       */
  879.         case 0x0e:      /* 640 x 200 16-color EGA                       */
  880.  
  881.           memcpy(ega_palp, pcx_EGA_DefPal_1, PCX_PAL_SIZE);
  882.  
  883.           break;
  884.  
  885.         case 0x0f:      /* 640 x 350 2-color EGA                        */
  886.  
  887.           memcpy(ega_palp, pcx_EGA_DefPal_2, PCX_PAL_SIZE);
  888.  
  889.           break;
  890.  
  891.         case 0x10:      /* 640 x 350 16-color EGA                       */
  892.  
  893.           memcpy(ega_palp, pcx_EGA_DefPal_3, PCX_PAL_SIZE);
  894.  
  895.           break;
  896.  
  897.         default:        /* (Should never reach here)                    */
  898.  
  899.           break;
  900.       }
  901.     }
  902.  
  903.     /* Map the EGA/VGA palette to the PCX file header palette           */
  904.  
  905.     for (i = 0; i < PCX_PAL_SIZE; i++)
  906.     {
  907.       val = (int) ega_palp[i];  /* Get current color palette value      */
  908.  
  909.       /* Extract color values                                           */
  910.  
  911.       red = ((val & 0x20) >> 5) | ((val & 0x04) >> 1);
  912.       green = ((val & 0x10) >> 4) | (val & 0x02);
  913.       blue = ((val & 0x08) >> 3) | ((val & 0x01) << 1);
  914.  
  915.       /* Map each color to a 6-bit value.  Only the top two bits are    */
  916.       /* significant for EGA displays.  The lower four bits (which      */
  917.       /* repeat the top two bits) are significant when the image is     */
  918.       /* presented on a VGA display emulating an EGA display.           */
  919.  
  920.       palettep[i].red = (BYTE) ((red << 6) | (red << 4) | (red << 2));
  921.       palettep[i].green = (BYTE) ((green << 6) | (green << 4) | (green <<
  922.           2));
  923.       palettep[i].blue = (BYTE) ((blue << 6) | (blue << 4) | (blue << 2));
  924.     }
  925.   }
  926.  
  927.   free(ega_palp);       /* Free the EGA/VGA palette buffer              */
  928.  
  929.   return (TRUE);
  930. }
  931.  
  932. /*
  933.  *************************************************************************
  934.  *
  935.  *  PCX_WRITE_LINE - Write PCX Line
  936.  *
  937.  *  Purpose:    To write an image scan line to a PCX-format image file.
  938.  *
  939.  *  Setup:      static BOOL pcx_write_line
  940.  *              (
  941.  *                unsigned char *linep,
  942.  *                int buflen,
  943.  *                FILE *fp
  944.  *              )
  945.  *
  946.  *  Where:      linep is a PCX scan line buffer pointer.
  947.  *              buflen is the length of the image scan line buffer in
  948.  *                bytes.
  949.  *              fp is a file pointer.
  950.  *
  951.  *  Return:     TRUE if successful; otherwise FALSE.
  952.  *
  953.  *  Note:       The PCX scan line buffer is assumed to contain the color
  954.  *              plane scan lines in sequence, with padding for an even
  955.  *              number of bytes and trailing "white" data for each line as
  956.  *              appropriate.
  957.  *
  958.  *************************************************************************
  959.  */
  960.  
  961. static BOOL pcx_write_line
  962. (
  963.   unsigned char *linep,
  964.   int buflen,
  965.   FILE *fp
  966. )
  967. {
  968.   int curr_data;        /* Current data byte                            */
  969.   int prev_data;        /* Previous data byte                           */
  970.   int data_count;       /* Data repeat count                            */
  971.   int line_count;       /* Scan line byte count                         */
  972.  
  973.   prev_data = *linep++;         /* Initialize the previous data byte    */
  974.   data_count = 1;
  975.   line_count = 1;
  976.  
  977.   while (line_count < buflen)   /* Encode scan line                     */
  978.   {
  979.     curr_data = *linep++;       /* Get the current data byte            */
  980.     line_count++;               /* Increment the scan line counter      */
  981.  
  982.     if (curr_data == prev_data)         /* Repeating data bytes ?       */
  983.     {
  984.       data_count++;     /* Increment the data repeat count              */
  985.  
  986.       /* Check for maximum allowable repeat count                       */
  987.  
  988.       if (data_count == PCX_COMP_MASK)
  989.       {
  990.         /* Encode the data                                              */
  991.  
  992.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  993.           return (FALSE);
  994.  
  995.         data_count = 0;         /* Reset the data repeat count          */
  996.       }
  997.     }
  998.     else    /* End of repeating data bytes                              */
  999.     {
  1000.       if (data_count > 0)
  1001.       {
  1002.         /* Encode the data                                              */
  1003.  
  1004.         if (pcx_encode(prev_data, data_count, fp) == FALSE)
  1005.           return (FALSE);
  1006.       }
  1007.  
  1008.       prev_data = curr_data;    /* Current data byte now previous       */
  1009.       data_count = 1;
  1010.     }
  1011.   }
  1012.  
  1013.   if (data_count > 0)   /* Any remaining data ?                         */
  1014.   {
  1015.     /* Encode the data                                                  */
  1016.  
  1017.     if (pcx_encode(prev_data, data_count, fp) == FALSE)
  1018.       return (FALSE);
  1019.   }
  1020.  
  1021.   return (TRUE);
  1022. }
  1023.  
  1024. /*
  1025.  *************************************************************************
  1026.  *
  1027.  *  PCX_ENCODE - Encode Byte Pair
  1028.  *
  1029.  *  Purpose:    To write an encoded byte pair (or a single unencoded
  1030.  *              byte) to a PCX-format image file.
  1031.  *
  1032.  *  Setup:      static BOOL pcx_encode
  1033.  *              (
  1034.  *                int data,
  1035.  *                int count,
  1036.  *                FILE *fp
  1037.  *              )
  1038.  *
  1039.  *  Where:      data is the data byte to be encoded (if necessary).
  1040.  *              count is the number of times the data byte is repeated in
  1041.  *                the image data.
  1042.  *              fp is a pointer to the PCX-format file the encoded byte
  1043.  *                pair or single byte is to be written to.
  1044.  *
  1045.  *  Return:     TRUE if successful; otherwise FALSE.
  1046.  *
  1047.  *************************************************************************
  1048.  */
  1049.  
  1050. static BOOL pcx_encode
  1051. (
  1052.   int data,
  1053.   int count,
  1054.   FILE *fp
  1055. )
  1056. {
  1057.   if (((data & PCX_COMP_FLAG) == PCX_COMP_FLAG) || count > 1)
  1058.   {
  1059.     /* Write the count byte                                             */
  1060.  
  1061.     if (putc(PCX_COMP_FLAG | count, fp) == EOF)
  1062.       return (FALSE);
  1063.   }
  1064.  
  1065.   /* Write the data byte                                                */
  1066.  
  1067.   if (putc(data, fp) == EOF)
  1068.     return (FALSE);
  1069.  
  1070.   return (TRUE);
  1071. }
  1072.  
  1073. /*
  1074.  *************************************************************************
  1075.  *
  1076.  *  PCX_WRITE_EXTPAL - Write Extended Palette
  1077.  *
  1078.  *  Purpose:    To read the current 256-color VGA palette and write an
  1079.  *              equivalent extended PCX palette to a PCX-format image
  1080.  *              file.
  1081.  *
  1082.  *  Setup:      static BOOL pcx_write_extpal
  1083.  *              (
  1084.  *                FILE *fp
  1085.  *              )
  1086.  *
  1087.  *  Where:      fp is a file pointer.
  1088.  *
  1089.  *  Return:     TRUE if successful; otherwise FALSE.
  1090.  *
  1091.  *************************************************************************
  1092.  */
  1093.  
  1094. static BOOL pcx_write_extpal
  1095. (
  1096.   FILE *fp
  1097. )
  1098. {
  1099.   int i;                        /* Scratch counter                      */
  1100.   BOOL status = TRUE;           /* Return status                        */
  1101.   PCX_PAL *palettep;            /* Extended PCX palette buffer pointer  */
  1102.   unsigned char *vga_palp;      /* 256-color VGA palette buffer pointer */
  1103.   union REGS regs;              /* 80x86 register values                */
  1104.   struct SREGS sregs;           /* 80x86 segment register values        */
  1105.  
  1106.   /* Allocate an extended PCX palette buffer                            */
  1107.  
  1108.   if ((palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL), PCX_EPAL_SIZE)) ==
  1109.       (PCX_PAL *) NULL)
  1110.     return (FALSE);
  1111.  
  1112.   /* Allocate a 256-color VGA palette buffer                            */
  1113.  
  1114.   if ((vga_palp = (unsigned char *) calloc(sizeof(unsigned char), 768))
  1115.       == (unsigned char *) NULL)
  1116.   {
  1117.     free(palettep);     /* Free the extended PCX palette buffer         */
  1118.     return (FALSE);
  1119.   }
  1120.  
  1121.   /* Read the current VGA palette (DAC registers)                       */
  1122.  
  1123.   regs.h.ah = 0x10;     /* Select "Read DAC Registers" BIOS routine     */
  1124.   regs.h.al = 0x17;
  1125.   regs.x.bx = 0;        /* Read all 256 DAC registers                   */
  1126.   regs.x.cx = 256;
  1127.   
  1128.   /* Get the VGA palette buffer offset value                            */
  1129.  
  1130.   regs.x.dx = (unsigned int) vga_palp;
  1131.  
  1132.   segread(&sregs);      /* Get the current DS segment register value    */
  1133.  
  1134.   sregs.es = sregs.ds;
  1135.  
  1136.   int86x(0x10, ®s, ®s, &sregs);   /* Call BIOS video service      */
  1137.  
  1138.   /* Map the VGA palette to an extended PCX palette                     */
  1139.  
  1140.   for (i = 0; i < PCX_EPAL_SIZE; i++)
  1141.   {
  1142.     palettep[i].red = (BYTE) (vga_palp[i * 3] << 2);
  1143.     palettep[i].green = (BYTE) (vga_palp[i * 3 + 1] << 2);
  1144.     palettep[i].blue = (BYTE) (vga_palp[i * 3 + 2] << 2);
  1145.   }
  1146.  
  1147.   /* Write the extended PCX palette indicator byte to the file          */
  1148.  
  1149.   if (status == TRUE)
  1150.     if (fputc(PCX_EPAL_FLAG, fp) == EOF)
  1151.       status = FALSE;
  1152.  
  1153.   /* Write the extended PCX palette to the file                         */
  1154.  
  1155.   if (status == TRUE)
  1156.     if (fwrite(palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, fp) !=
  1157.         PCX_EPAL_SIZE)
  1158.       status = FALSE;
  1159.  
  1160.   free(palettep);       /* Free the extended PCX palette buffer         */
  1161.  
  1162.   free(vga_palp);       /* Free the VGA palette buffer                  */
  1163.  
  1164.   return (status);
  1165. }
  1166.  
  1167. /*
  1168.  *************************************************************************
  1169.  *
  1170.  *  PCX_GET_HERC - Get Hercules Scan Line
  1171.  *
  1172.  *  Purpose:    To read a Hercules monochrome graphics display adapter
  1173.  *              scan line into a buffer.
  1174.  *
  1175.  *  Setup:      static void pcx_get_herc
  1176.  *              (
  1177.  *                PCX_WORKBLK *wbp,
  1178.  *                unsigned char _far *linep,
  1179.  *                int line_num
  1180.  *              )
  1181.  *
  1182.  *  Where:      wbp is a PCX workblock pointer.
  1183.  *              linep is a pointer to where the scan line is to be
  1184.  *                returned.
  1185.  *              line_num is the scan line number.
  1186.  *
  1187.  *************************************************************************
  1188.  */
  1189.  
  1190. static void pcx_get_herc
  1191. (
  1192.   PCX_WORKBLK *wbp,
  1193.   unsigned char _far *linep,
  1194.   int line_num
  1195. )
  1196. {
  1197.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1198.  
  1199.   /* Calculate Hercules display buffer pointer                          */
  1200.  
  1201.   displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) +
  1202.       ((line_num >> 2) * 90) + 0x2000 * (line_num & 3);
  1203.  
  1204.   /* Copy data from the Hercules display buffer to the scan line buffer */
  1205.  
  1206.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1207.  
  1208.   /* Mask off unseen pixels                                             */
  1209.  
  1210.   linep[wbp->num_bytes - 1] |= wbp->mask;
  1211.  
  1212.   /* Pad scan line with "white" data byte (if necessary)                */
  1213.  
  1214.   if (wbp->num_bytes & 1)
  1215.     linep[wbp->num_bytes] = 0xff;
  1216. }
  1217.  
  1218. /*
  1219.  *************************************************************************
  1220.  *
  1221.  *  PCX_GET_CGA - Get CGA Scan Line
  1222.  *
  1223.  *  Purpose:    To read a CGA display adapter scan line into a buffer.
  1224.  *
  1225.  *  Setup:      static void pcx_get_cga
  1226.  *              (
  1227.  *                PCX_WORKBLK *wbp,
  1228.  *                unsigned char _far *linep,
  1229.  *                int line_num
  1230.  *              )
  1231.  *
  1232.  *  Where:      wbp is a PCX workblock pointer.
  1233.  *              linep is a pointer to where the scan line is to be
  1234.  *                returned.
  1235.  *              line_num is the scan line number.
  1236.  *
  1237.  *************************************************************************
  1238.  */
  1239.  
  1240. static void pcx_get_cga
  1241. (
  1242.   PCX_WORKBLK *wbp,
  1243.   unsigned char _far *linep,
  1244.   int line_num
  1245. )
  1246. {
  1247.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1248.  
  1249.   /* Calculate CGA display buffer pointer                               */
  1250.  
  1251.   displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80)
  1252.       + 0x2000 * (line_num & 1);
  1253.  
  1254.   /* Copy data from the CGA display buffer to the scan line buffer      */
  1255.  
  1256.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1257.  
  1258.   /* Mask off unseen pixels                                             */
  1259.  
  1260.   linep[wbp->num_bytes - 1] |= wbp->mask;
  1261.  
  1262.   /* Pad scan line with "white" data byte (if necessary)                */
  1263.  
  1264.   if (wbp->num_bytes & 1)
  1265.     linep[wbp->num_bytes] = 0xff;
  1266. }
  1267.  
  1268. /*
  1269.  *************************************************************************
  1270.  *
  1271.  *  PCX_GET_EGA - Get EGA/VGA Scan Line
  1272.  *
  1273.  *  Purpose:    To read an EGA/VGA display adapter scan line into a
  1274.  *              buffer.
  1275.  *
  1276.  *  Setup:      static void pcx_get_ega
  1277.  *              (
  1278.  *                PCX_WORKBLK *wbp,
  1279.  *                unsigned char _far *linep,
  1280.  *                int line_num
  1281.  *              )
  1282.  *
  1283.  *  Where:      wbp is a PCX workblock pointer.
  1284.  *              linep is a pointer to where the scan line is to be
  1285.  *                returned.
  1286.  *              line_num is the scan line number.
  1287.  *
  1288.  *************************************************************************
  1289.  */
  1290.  
  1291. static void pcx_get_ega
  1292. (
  1293.   PCX_WORKBLK *wbp,
  1294.   unsigned char _far *linep,
  1295.   int line_num
  1296. )
  1297. {
  1298.   int plane_num;                /* EGA/VGA color plane number           */
  1299.   unsigned char _far *displayp; /* Display buffer pointer               */
  1300.  
  1301.   /* Calculate buffer pointer                                           */
  1302.  
  1303.   displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) +
  1304.       line_num * 80;
  1305.  
  1306.   /* Copy PCX scan line data from each color plane                      */
  1307.  
  1308.   for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++)
  1309.   {
  1310.     /* Select the current color plane in EGA/VGA Read Mode 0            */
  1311.  
  1312.     outpw(0x03ce, (plane_num << 8) | 0x04);
  1313.  
  1314.     /* Copy data from the EGA/VGA display to the scan line buffer       */
  1315.  
  1316.     (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1317.  
  1318.     /* Mask off unseen pixels                                           */
  1319.  
  1320.     linep[wbp->num_bytes - 1] |= wbp->mask;
  1321.  
  1322.     /* Pad plane scan line with "white" data byte (if necessary)        */
  1323.  
  1324.     if (wbp->num_bytes & 1)
  1325.       linep[wbp->num_bytes] = 0xff;
  1326.  
  1327.     linep += wbp->header.bppscan;       /* Increment plane offset       */
  1328.   }
  1329.  
  1330.   /* Select EGA/VGA Write Mode 0 with all color planes enabled          */
  1331.  
  1332.   outpw(0x03c4, 0x0f02);
  1333. }
  1334.  
  1335. /*
  1336.  *************************************************************************
  1337.  *
  1338.  *  PCX_GET_VGA - Get VGA Scan Line
  1339.  *
  1340.  *  Purpose:    To read a VGA display adapter scan line into a buffer.
  1341.  *
  1342.  *  Setup:      static void pcx_get_vga
  1343.  *              (
  1344.  *                PCX_WORKBLK *wbp,
  1345.  *                unsigned char _far *linep,
  1346.  *                int line_num
  1347.  *              )
  1348.  *
  1349.  *  Where:      wbp is a PCX workblock pointer.
  1350.  *              linep is a pointer to where the scan line is to be
  1351.  *                returned.
  1352.  *              line_num is the scan line number.
  1353.  *
  1354.  *************************************************************************
  1355.  */
  1356.  
  1357. static void pcx_get_vga
  1358. (
  1359.   PCX_WORKBLK *wbp,
  1360.   unsigned char _far *linep,
  1361.   int line_num
  1362. )
  1363. {
  1364.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1365.  
  1366.   /* Calculate buffer pointer                                           */
  1367.  
  1368.   displayp = (unsigned char _far *) 0xa0000000L + line_num * 320;
  1369.  
  1370.   /* Copy data from the VGA display buffer to the scan line buffer      */
  1371.  
  1372.   (void) _fmemcpy(linep, displayp, wbp->num_bytes);
  1373.  
  1374.   /* Pad scan line with "white" data byte (if necessary)                */
  1375.  
  1376.   if (wbp->num_bytes & 1)
  1377.     linep[wbp->num_bytes] = 0xff;
  1378. }
  1379.  
  1380.